﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. 
// See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Fabric;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ActorAnalyzer
{
    public partial class ActorChooser : Form
    {
        public string ChosenUri = null;
        public string ChosenPartitionName = null;

        public ActorChooser(string fabricConnectionString)
        {
            InitializeComponent();
            label1.Text = "Fabric Connection String: " + fabricConnectionString;
            PopulateActors(fabricConnectionString);
        }

        private async void PopulateActors(string fabricConnectionString)
        {
            FabricClient client = new FabricClient(new string[] {fabricConnectionString});
            Uri subName = new Uri("fabric:/actor");
            List<string> choices = new List<string>();

            // Do the whole loop on a ThreadPool task because a couple of parts of it
            // (EnumerateSubNamesAsync && nameResult.HasMoreData) really don't like being
            // on the UI thread.
            await Task.Factory.StartNew(() =>
            {
                try
                {
                    NameEnumerationResult nameResult = null;
                    do
                    {
                        // See what actor URI's exist.
                        Task<NameEnumerationResult> enumTask = client.PropertyManager.EnumerateSubNamesAsync(subName, nameResult, true);
                        nameResult = enumTask.Result;

                        // Each batch has two flags: HasMore and Consistent. 
                        // Consistent indicates whether the relevant naming data in the cluster is currently being updated 
                        // HasMore indicates whether there are othe batches that remain.
                        // If there are other batches, the user needs to recall the EnumerateSubNamesAsync and give the latest batch as the previousResult.
                        // PreviousResult makes sure that the subsequent batch is returned.                    
                        foreach (Uri name in nameResult)
                        {
                            var s = name.ToString();
                            if (s.Count(c => c == '/') > 2)
                            {
                                // This is an actor, not an app
                                choices.Add(s);
                            }
                        }
                    } while (nameResult.HasMoreData);

                }
                catch (AggregateException ae)
                {
                    if (!(ae.GetBaseException() is FabricElementNotFoundException))
                        throw;
                }
                catch (Exception e)
                {
                    if (!(e is FabricElementNotFoundException))
                    {
                        MessageBox.Show("Exception when enumerating actors: " + e.Message, "ERROR");
                        Close();
                    }
                }
            });

            listBoxActors.Items.AddRange(choices.ToArray<Object>());
        }

        private void buttonSelect_Click(object sender, EventArgs e)
        {
            int idx = listBoxActors.SelectedIndex;
            ChosenUri = (string)listBoxActors.Items[idx];
            ChosenPartitionName = String.IsNullOrEmpty(partitionNameTextBox.Text) ? null : partitionNameTextBox.Text;
            Close();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void listBoxActors_SelectedIndexChanged(object sender, EventArgs e)
        {
            buttonSelect.Enabled = true;
        }
    }
}
